import copy
import logging

from fastapi import FastAPI

from wintersweet import project_label
from wintersweet.asyncs.ntp import IntervalNTPClientManager
from wintersweet.asyncs.task import TaskManager
from wintersweet.utils.base import Utils
from wintersweet.utils.logging import register_logger
from wintersweet.asyncs.pool.mysql import mysql_pool_manager
from wintersweet.asyncs.pool.redis import redis_pool_manager
from wintersweet.asyncs.pool.es import es_manager


DEFAULT_HEADERS = [(r'Server', project_label)]


class Launcher:
    app: FastAPI = None

    @classmethod
    def create_app(cls):
        if cls.app:
            return cls.app

        from wintersweet.framework.conf import settings

        settings.initialize()
        app_config = copy.deepcopy(settings.APP_CONFIG)
        on_startup = app_config.get('on_startup', [])
        on_shutdown = app_config.get('on_shutdown', [])
        assert isinstance(on_startup, (list, tuple)), 'on_startup must be list or tuple'
        _on_startup = [*on_startup]
        _on_shutdown = [*on_shutdown]
        app_config['on_startup'] = _on_startup

        if settings.ES_CONFIG:
            es_manager.register(settings.ES_CONFIG)
            _on_startup.insert(0, es_manager.initialize)

        if settings.REDIS_CONFIG:
            redis_pool_manager.register(settings.REDIS_CONFIG)
            _on_startup.insert(0, redis_pool_manager.initialize)

        if settings.DATABASES:
            mysql_pool_manager.register(settings.DATABASES)
            _on_startup.insert(0, mysql_pool_manager.initialize)

        task_manager = None
        if settings.INTERVAL_TASKS or settings.CRONTAB_TASKS:
            task_manager = TaskManager()
            if settings.INTERVAL_TASKS:
                for item in settings.INTERVAL_TASKS:
                    interval, func = item
                    task_manager.add_interval_task(interval, func)

            if settings.CRONTAB_TASKS:
                for item in settings.CRONTAB_TASKS:
                    crontab, func = item
                    task_manager.add_crontab_task(crontab, func)

            _on_startup.append(task_manager.register)
            _on_shutdown.append(task_manager.shutdown)

        ntp_manager = None
        if settings.NTP_CONFIG and settings.NTP_CONFIG.get('hosts'):
            ntp_manager = IntervalNTPClientManager(**settings.NTP_CONFIG)
            _on_startup.append(ntp_manager.initialize)
            _on_shutdown.append(ntp_manager.shutdown)

        cls.app = FastAPI(**app_config)
        cls.app.state.task = task_manager
        cls.app.state.ntp = ntp_manager

        logging.getLogger(r'fastapi').setLevel(settings.LOGGING_CONFIG['level'].upper())

        for middleware in settings.MIDDLEWARES:
            cls.app.add_middleware(middleware['cls'], **middleware.get('options', {}))

        for exception_handler in settings.EXCEPTION_HANDLERS:
            cls.app.add_exception_handler(exception_handler['cls'], exception_handler['handler'])

        register_logger(
            **settings.LOGGING_CONFIG,
            debug=settings.DEBUG
        )
        Utils.log.info(
            f'Started By {project_label}'
        )
        return cls.app

